﻿using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;
using MugenMvvmToolkit.Infrastructure;
using MugenMvvmToolkit.Interfaces;
using MugenMvvmToolkit.Interfaces.ViewModels;
using MugenMvvmToolkit.Models;
using MugenMvvmToolkit.Utils;
using MugenMvvmToolkit.ViewModels;

namespace MugenMvvmToolkitTest.TestInfrastructure
{
    [TestClass]
    public abstract class TestBase
    {
        #region Properties

        protected List<Type> CanBeResolvedTypes { get; private set; }

        protected TestViewManager ViewManager { get; set; }

        protected TestViewModelSettings Settings { get; set; }

        protected TestThreadManager ThreadManager { get; set; }

        protected TestDisplayNameProvider DisplayNameProvider { get; set; }

        protected TestIocAdapter IocAdapter { get; set; }

        protected ViewModelProvider ViewModelProvider { get; set; }

#if !NOVISUALSTATE
        protected TestVisualStateManager VisualStateManager { get; set; }
#endif

        #endregion

        #region Methods

        [TestInitialize]
        public void SetUp()
        {
            CanBeResolvedTypes = new List<Type>
            {
                typeof (IThreadManager),
                typeof (IViewModelSettings),
                typeof (IViewManager),
                typeof (IDisplayNameProvider),
                typeof(IViewModelProvider),
#if !NOVISUALSTATE
                typeof(IVisualStateManager)
#endif
            };
            ViewManager = new TestViewManager();
            ThreadManager = new TestThreadManager();
            GlobalSettings.DefaultThreadManager = ThreadManager;
            Settings = new TestViewModelSettings();
            GlobalSettings.DefaultViewModelSettings = Settings;
            DisplayNameProvider = new TestDisplayNameProvider();
            IocAdapter = new TestIocAdapter
            {
                GetFunc = GetFunc,
                CanResolveDelegate = CanResolve
            };
            ViewModelProvider = new ViewModelProvider(IocAdapter);
            OnInit();
        }

        protected T GetViewModel<T>(IActivationPolicy policy = null) where T : IViewModel, new()
        {
            if (policy == null)
                policy = GlobalSettings.DefaultActivationPolicy;
            var vm = new T();
            InitializeViewModel(vm, IocAdapter, policy);
            return vm;
        }

        protected void ShouldThrow<T>(Action action) where T : Exception
        {
            try
            {
                action();
            }
            catch (Exception exception)
            {
#if TASKSUPPORT
                var aggregateException = exception as AggregateException;
                if (aggregateException != null)
                    exception = GetOriginalException(aggregateException);
#endif
                if (!(exception is T))
                    throw new InvalidOperationException(string.Format("The exception is wrong {0}.", exception));
                return;
            }
            throw new InvalidOperationException(string.Format("The exception {0} was not thrown.", typeof(T)));
        }

        protected void ShouldThrow(Action action)
        {
            ShouldThrow<Exception>(action);
        }

        protected void InitializeViewModel(IViewModel viewModel, IIocAdapter iocAdapter, IActivationPolicy policy = null, IViewModel parentViewModel = null)
        {
            if (viewModel.IsInitialized)
                return;
            var initializationContext = new InitializationContext(iocAdapter, policy, viewModel)
            {
                ParentViewModel = parentViewModel,
                ViewModel = viewModel
            };
            viewModel.InitializeViewModel(initializationContext);
        }

        protected virtual object GetFunc(Type type, string s, IIocParameter[] arg3)
        {
            if (type == typeof(IThreadManager))
                return ThreadManager;
            if (type == typeof(IViewModelSettings))
                return Settings;
            if (type == typeof(IViewManager))
                return ViewManager;
            if (type == typeof(IDisplayNameProvider))
                return DisplayNameProvider;
#if !NOVISUALSTATE
            if (type == typeof(IVisualStateManager))
                return VisualStateManager;
#endif
            if (type == typeof(IViewModelProvider))
                return ViewModelProvider;
            return Activator.CreateInstance(type);
        }

#if TASKSUPPORT
        protected Exception GetOriginalException(AggregateException aggregateException)
        {
            Exception exception = aggregateException;
            while (aggregateException != null)
            {
                exception = aggregateException.InnerException;
                aggregateException = exception as AggregateException;
            }
            return exception;
        }
#endif


        private bool CanResolve(Type type)
        {
            return CanBeResolvedTypes.Contains(type);
        }

        protected virtual void OnInit()
        {
        }

        #endregion
    }
}